#include "StdAfx.h"
#include "Input.h"
#include <limits>


//-----------------------------------------------------------------------------
Input::KeyboardState	Input::Key			= {false};
Input::MouseState		Input::Mouse		= {false};
Input::PadState		Input::Pad			= {0};
bool						Input::UsingPad	= false;

//-----------------------------------------------------------------------------
void Input::GetAndReset(KeyboardState *k, MouseState *m, PadState *p)
{
	if(k)	{	*k = Key;		memset(&Key,	0, sizeof(KeyboardState));	}
	if(m)	{	*m = Mouse;		memset(&Mouse,	0, sizeof(MouseState));		}
	if(p)	{	*p = Pad;		memset(&Pad,	0, sizeof(PadState));		}
}


//-----------------------------------------------------------------------------
bool Input::HandleMouseEvent(MSG &msg)
{
	switch(msg.message)
	{
	case WM_LBUTTONDOWN:	Mouse.LButton	= true;	return true;
	case WM_RBUTTONDOWN:	Mouse.RButton	= true;	return true;
	case WM_MOUSEWHEEL:
		{
			short zDelta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
			if(zDelta > 0)	Mouse.ScrollUp		= true;
			else				Mouse.ScrollDown	= true;
			return true;
		}
	}

	return false;
}


//-----------------------------------------------------------------------------
bool Input::HandleKeyEvent(MSG &msg)
{
	if(msg.message == WM_KEYUP)
		return false;

	Key.LastKey = msg.wParam;
	Key.LastPar = msg.lParam;
	Key.LastExt = (Key.LastPar & (1<<24)) != 0;

//	std::cout << Key.LastKey << std::endl;

	UsingPad = false;

	switch(Key.LastKey)
	{
	case VK_ESCAPE:	Key.Escape	= true;	return true;
	case VK_RETURN:	Key.Return	= true;	return true;
	case VK_SPACE:		Key.Space	= true;	return true;
	case VK_BACK:		Key.Back		= true;	return true;
	case VK_UP:			Key.Up		= true;	return true;
	case VK_DOWN:		Key.Down		= true; 	return true;
	case VK_LEFT:		Key.Left		= true; 	return true;
	case VK_RIGHT:		Key.Right	= true; 	return true;
	case VK_MULTIPLY:	Key.Multiply= true; 	return true;
	case VK_ADD:		Key.Add		= true; 	return true;
	case VK_SUBTRACT:	Key.Subtract= true; 	return true;
	case VK_DIVIDE:	Key.Divide	= true; 	return true;
/*	case VK_F1:			Key.F1		= true; 	return true;
	case VK_F2:			Key.F2		= true; 	return true;
	case VK_F3:			Key.F3		= true; 	return true;
	case VK_F4:			Key.F4		= true; 	return true;
*/	}

	return false;
}


//-----------------------------------------------------------------------------
void Input::UpdateXInput()
{
	static XINPUT_STATE LastState = {0};

	DWORD	result = XInputGetState(0, &Pad.State);

	WORD	currButtons = Pad.State.Gamepad.wButtons,
			prevButtons = LastState.Gamepad.wButtons;

	if(currButtons)
		UsingPad = true;

	Pad.A			= 0!=(currButtons&XINPUT_GAMEPAD_A)					&& 0==(prevButtons&XINPUT_GAMEPAD_A);
	Pad.B			= 0!=(currButtons&XINPUT_GAMEPAD_B)					&& 0==(prevButtons&XINPUT_GAMEPAD_B);
	Pad.X			= 0!=(currButtons&XINPUT_GAMEPAD_X)					&& 0==(prevButtons&XINPUT_GAMEPAD_X);
	Pad.Y			= 0!=(currButtons&XINPUT_GAMEPAD_Y)					&& 0==(prevButtons&XINPUT_GAMEPAD_Y);
	Pad.D_Up		= 0!=(currButtons&XINPUT_GAMEPAD_DPAD_UP)			&& 0==(prevButtons&XINPUT_GAMEPAD_DPAD_UP);
	Pad.D_Down	= 0!=(currButtons&XINPUT_GAMEPAD_DPAD_DOWN)		&& 0==(prevButtons&XINPUT_GAMEPAD_DPAD_DOWN);
	Pad.D_Left	= 0!=(currButtons&XINPUT_GAMEPAD_DPAD_LEFT)		&& 0==(prevButtons&XINPUT_GAMEPAD_DPAD_LEFT);
	Pad.D_Right	= 0!=(currButtons&XINPUT_GAMEPAD_DPAD_RIGHT)		&& 0==(prevButtons&XINPUT_GAMEPAD_DPAD_RIGHT);
	Pad.Start	= 0!=(currButtons&XINPUT_GAMEPAD_START)			&& 0==(prevButtons&XINPUT_GAMEPAD_START);
	Pad.Back		= 0!=(currButtons&XINPUT_GAMEPAD_BACK)				&& 0==(prevButtons&XINPUT_GAMEPAD_BACK);
	Pad.L			= 0!=(currButtons&XINPUT_GAMEPAD_LEFT_SHOULDER)	&& 0==(prevButtons&XINPUT_GAMEPAD_LEFT_SHOULDER);
	Pad.R			= 0!=(currButtons&XINPUT_GAMEPAD_RIGHT_SHOULDER)&& 0==(prevButtons&XINPUT_GAMEPAD_RIGHT_SHOULDER);

//----
//	remove thumbstick deadzone and normalize
	Pad.LThumb.x = (double)Pad.State.Gamepad.sThumbLX;
	Pad.LThumb.y = (double)Pad.State.Gamepad.sThumbLY;
	Pad.RThumb.x = (double)Pad.State.Gamepad.sThumbRX;
	Pad.RThumb.y = (double)Pad.State.Gamepad.sThumbRY;

	double	squaredNormL = Pad.LThumb.normSquared(),
				squaredNormR = Pad.RThumb.normSquared();
//----
	if(squaredNormL > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE*XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
	{
		double norm = sqrt(squaredNormL),
				 f = 1.0 / norm;

	//	normalized direction
		Pad.LThumb *= f;

	//	clip the magnitude at its expected maximum value
		if(norm > 32767.0)
			norm = 32767.0;

	//	adjust magnitude relative to the end of the dead zone
		norm -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;

	//	normalize the magnitude with respect to its expected range
		norm *= 4.0131631752147042298739866762983e-5;
//	=	norm /= (32767 - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);

		Pad.LThumb *= norm;					// should now be between (-1,1)
	}
	else
	{
		Pad.LThumb.x =
		Pad.LThumb.y = 0;
	}

//----
	if(squaredNormR > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE*XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
	{
		double norm = sqrt(squaredNormR),
				 f = 1.0 / norm;

	//	normalized direction
		Pad.RThumb *= f;

	//	clip the magnitude at its expected maximum value
		if(norm > 32767.0)
			norm = 32767.0;

	//	adjust magnitude relative to the end of the dead zone
		norm -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;

	//	normalize the magnitude with respect to its expected range
		norm *= 4.153168867846166625134977988205e-5;
//	=	norm /= (32767 - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);

		Pad.RThumb *= norm;					// should now be between (-1,1)
	}
	else
	{
		Pad.RThumb.x =
		Pad.RThumb.y = 0;
	}
	

//----
//	save state
	LastState = Pad.State;
}

